<?php
	include("$GLOBALS[dir_root]/conf.php");
	include_once("$GLOBALS[dir_interface]/IModule.php");
	include_once("$GLOBALS[dir_abstract]/ALogger.php");
	include_once("$GLOBALS[dir_class]/CDB.php");
	include_once("$GLOBALS[dir_class]/CUser.php");
	include_once("$GLOBALS[dir_module]/html/MHtml.php");
	include_once("$GLOBALS[dir_function]/string.php");

	class CLGroup extends ALogger
	{
		public $name;
		public $chl;

		public function __construct($name)
		{
			$this->name = $name;
			$this->chl = array();
			$this->chl[0] = array();
		}

		public function display($all = false)
		{
			$ret = "";
			foreach($this->chl as $k => $g)
			{
				$kk = "$k";
				if(($kk=="0" && $all) || $kk!="0")
				{
					foreach($g as $o)
					{
						if($o instanceof CLGroup) $ret .= $o->display();
						elseif($o instanceof CLModuleContainer)$ret .= $o->display();
						else $ret .= $o."\n";
					}
				}
			}
			return $ret;
		}

		public function __clone()
		{
			foreach($this->chl as $k1 => $inst)
			foreach($inst as $k2 => $o)
				if($o instanceof CLGroup)
					$this->chl[$k1][$k2] = clone $o;
				elseif($o instanceof CLModuleContainer)
					$this->chl[$k1][$k2] = clone $o;
		}


		public function instance($new)
		{
			$this->chl[$new] = array();
			foreach($this->chl[0] as $k => $o)
				if($o instanceof CLGroup)
					$this->chl[$new][$k] = clone $o;
				elseif($o instanceof CLModuleContainer)
					$this->chl[$new][$k] = clone $o;
				else
					$this->chl[$new][$k] = $o;
			return $this->chl[$new];
		}

		// ricerca di un modulo ricorsivamente all'interno dell'albero oggetti
		public function findModule($name)
		{
			foreach($this->chl as $o)
				if($o instanceof CLGroup && ($ret=$o->getModule($name))!=null)
					return $ret;
				elseif($o instanceof CLModuleContainer && $o->equals($name))
					return $o;
			return null;
		}
	}

	class CLModuleContainer extends ALogger
	{
		public $name;
		private $_params;
		private $_module;
		private $_ready;

		public function __construct($name, $params)
		{
			$this->name = $name;
			$this->_params = $params;
			$this->_module = "[$name]";
			$this->_ready = false;
		}

		public function setModule(AModule &$m)
		{
			$this->_module = $m;
			$this->_ready = true;
		}

		public function display()
		{
			if($this->_ready) return $this->_module->display();
			return $this->_module;
		}

		public function equals($name)
		{
			return $this->name == $name;
		}
	}

	class CLayout extends ALogger
	{
		private $_content;
		private $_ready;
		private $_token;
		private $_defmodule;
		private $_file;
		private $_root;

		public function __construct($name = "unnamedLayout")
		{
			$this->name = $name;
			$this->_ready = false;
		}

		public function __destruct()
		{
		}

		public function loadLayout($fileName)
		{
			if(file_exists($fileName))
			{
				$this->_content = html_trim(file_get_contents($fileName));
				$this->_file = $fileName;
				$this->parseContent();
				$this->_ready = true;
			}
			else
			{
				$this->error("file not found $fileName");
			}
		}

		public function setModule($instance, $name, AModule &$module)
		{
			if($m=$this->getModule($instance, $name))
			{
				$m->setModule($module);
				return true;
			}
			else
			{
				$this->debug("module $name not found");
				return false;
			}
		}

		public function getModule($instance, $name)
		{
			foreach($this->_root->groups[$instance] as $m)
			{
				if($m instanceof CLModuleContainer && $m->name==$name) return $m;
			}
			return false;
		}

		public function getGroup($group_name)
		{
			foreach($this->_root->groups as $g)
				if($g->name==$group_name) return $g;
			return false;
		}

		public function instanceGroup($group_name, $new)
		{
			$grp = $this->getGroup($group_name);
			if(!$grp)
			{
				$this->debug("no group $group_name found");
				return false;
			}
			$inst = $grp->instance($new);
			$this->_root->groups[$new] = $inst;
			//print_r($this->_root->groups);
			//$this->debug("instanced group $new");
			return $inst;
		}

		public function display()
		{
			//return "<pre>".htmlentities(print_r($this->_root, true))."</pre>";
			$this->debug("<pre>".htmlentities(print_r($this->_root, true))."</pre>");
			return $this->_root->display(true);
		}

		private function parseContent()
		{
			$this->_root = new CLGroup("root");
			$this->_root->groups = array();
			$this->_root->modules = array();
			$current = $this->_root;
			$stack = array();
			// OK --> preg_match_all("/<\/?(?P<name>group *|module *)(?P<attr>[^>\/]*)\/*>/", $data, $matches);
			preg_match_all("/<(\/?group|module) *([^>\/]*)\/*>/", $this->_content, $matches, PREG_OFFSET_CAPTURE);
			$lastpos = 0;
			foreach($matches[1] as $k => $m)
			{
				$tag = $m[0];
				$pos = $m[1];
				$atr = array();
				$count = 0;

				preg_match_all("/([^ ]*)=\"([^ ]*)\" */", $matches[2][$k][0], $attrs);
				foreach($attrs[1] as $atrk => $atr_name)
				{
					$atr[$atr_name] = $attrs[2][$atrk];
				}
				$count = count($current->chl[0]);
				if($tag=="group")
				{
					$current->chl[0][$count++] = substr($this->_content, $lastpos, $pos-$lastpos-1);
					array_push($stack, $current);
					$grp = new CLGroup($atr['name']);
					//$grp->att = $atr['name'];
					$current->chl[0][$count] = $grp;
					$this->_root->groups[count($this->_root->groups)] = &$current->chl[0][$count];
					$count++;
					$current = $grp;
				}
				elseif($tag=="/group")
				{
					$current->chl[0][$count++] = substr($this->_content, $lastpos, $pos-$lastpos-1);
					$current = array_pop($stack);
				}
				elseif($tag=="module")
				{
					if($this->getModule(0, $atr['name']))
					{
						$this->debug("modulo $atr[name] duplicato");
					}
					$current->chl[0][$count++] = substr($this->_content, $lastpos, $pos-$lastpos-1);
					$current->chl[0][$count] = new CLModuleContainer($atr['name'], isset($atr['params'])?$atr['params']:"");
					$this->_root->modules[count($this->_root->modules)] = &$current->chl[0][$count];
					$count++;
				}
				else continue;
				$lastpos = $matches[0][$k][1] + strlen($matches[0][$k][0]);
			}
			$current->chl[0][$count] = substr($this->_content, $lastpos, strlen($this->_content)-$lastpos);
			//echo "fine parsing ".htmlentities($this->_content)."<br><br>";
			//$dup = $this->instanceGroup("group", "group2");
		}
	}
?>